#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/robo-module.h"
#include "ns3/flow-monitor-module.h"
#include "ns3/teama-module.h"
#include "ns3/teamb-module.h"

using namespace ns3;
using namespace std;

map<Address, string> gAddr2Robo;
void
BulidAddr2RoboMap (NodeContainer nodes)
{
  for (uint32_t i = 0; i < nodes.GetN (); ++i)
    {
      nodes.Get (i)->GetObject<Ipv4> ();
    }
}

int
main (int argc, char **argv)
{
  RoboJudge::Get ()->Init ();
  RoboTeamConfig cfg;
  cfg.push_back ({RoboTypeHero, "Hero", FVector (2, 1), FAngle (0)});
  cfg.push_back ({RoboTypeInfantry, "Infantry1", FVector (1, 3), FAngle (0)});
  //   cfg.push_back ({RoboTypeInfantry, "Infantry2", FVector (10, 1), FAngle (0)});
  //   cfg.push_back ({RoboTypeSentinel, "Sentinel", FVector (0, 0), FAngle (0)});
  // cfg.push_back ({RoboTypeEngineer, "Engineer", FVector (1, 2), FAngle (0)});
  //   cfg.push_back ({RoboTypeUVA, "UVA", FVector (5, 0.5), FAngle (0)});
  cfg.push_back ({RoboTypeTower, "Tower", FVector (1., 1.), FAngle (0)});
  RoboTeamHelper team1;
  team1.Init (1, FVector (0, 0), FAngle (0), cfg);
  RoboTeamHelper team2;
  team2.Init (2, FVector (28, 15), FAngle (PI), cfg);

  if (!EntryPoint_teama (team1))
    {
      std::cout << "Team A config error" << std::endl;
    }

  if (!EntryPoint_teamb (team2))
    {
      std::cout << "Team B config error" << std::endl;
    }

  NodeContainer allNodes (team1.GetNodes (), team2.GetNodes ());

  FlowMonitorHelper flowmon;
  Ptr<FlowMonitor> monitor = flowmon.Install (allNodes);

  NS_LOG_UNCOND ("Simulation start...");
  Simulator::Stop (Seconds (40));
  Simulator::Run ();
  monitor->CheckForLostPackets ();
  Ptr<Ipv4FlowClassifier> classifier = DynamicCast<Ipv4FlowClassifier> (flowmon.GetClassifier ());
  map<FlowId, FlowMonitor::FlowStats> stats = monitor->GetFlowStats ();

  double Throughput = 0.0;

  for (map<FlowId, FlowMonitor::FlowStats>::const_iterator i = stats.begin (); i != stats.end ();
       ++i)
    {
      Ipv4FlowClassifier::FiveTuple t = classifier->FindFlow (i->first);

      cout << "Flow ID: " << i->first << " Src Addr " << t.sourceAddress << " Dst Addr "
           << t.destinationAddress << endl;
      cout << "Tx Packets = " << i->second.txPackets << endl;
      cout << "Rx Packets = " << i->second.rxPackets << endl;
      cout << "Delay = " << i->second.delaySum / i->second.rxPackets << endl;
      cout << "Lost Packets = " << i->second.lostPackets << endl;

      Throughput =
          i->second.rxBytes * 8.0 /
          (i->second.timeLastRxPacket.GetSeconds () - i->second.timeFirstTxPacket.GetSeconds ()) /
          1024;
      cout << "Throughput: " << Throughput << " Kbps" << endl;
    }

  Simulator::Destroy ();
  NS_LOG_UNCOND ("End");

  return 0;
}